package cn.chen.server.adapter;

import java.io.UnsupportedEncodingException;
import java.net.InetSocketAddress;
import java.nio.charset.Charset;

import javax.annotation.Resource;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import cn.chen.server.dispatcher.RequestDispatcher;
import cn.chen.server.util.ChannelMap;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandler.Sharable;
import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;

/**
 * NettyServer通道适配器
 * 
 * @author wangchen
 * @Date 2019-02-28
 */
@Component
@Sharable
public class ServerChannelHandlerAdapter extends ChannelHandlerAdapter {
	private static final Logger LOGGER = LoggerFactory.getLogger(ServerChannelHandlerAdapter.class);
	/**
	 * 注入请求分排器
	 */
	@Resource
	private RequestDispatcher dispatcher;
	private int lossConnectCount = 0;

	@Override
	public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
		LOGGER.error("{} -> [连接异常] {}通道异常，异常原因：{}", this.getClass().getName(), ctx.channel().id(), cause.getMessage());
		ctx.close();
	}

	// 当channel注册的时候
	@Override
	public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
		InetSocketAddress insocket = (InetSocketAddress) ctx.channel().remoteAddress();
		String clientIP = insocket.getAddress().getHostAddress();
		Integer port = insocket.getPort();
		System.out.println("客户端已连接：" + clientIP + ":" + port);
		System.err.println(ctx.channel().id());
		ChannelMap.addChannel(String.valueOf(port), ctx);
		ctx.fireChannelRegistered();
	}

	// 当channel取消注册的时候
	@Override
	public void channelUnregistered(ChannelHandlerContext ctx) throws Exception {
		InetSocketAddress insocket = (InetSocketAddress) ctx.channel().remoteAddress();
		String clientIP = insocket.getAddress().getHostAddress();
		Integer port = insocket.getPort();
		System.out.println("客户端已断开：" + clientIP + ":" + port);
		System.err.println(ctx.channel().id());
		ctx.fireChannelUnregistered();
	}

	/**
	 * 服务器接收到消息时进行进行的处理
	 *
	 * @param channelHandlerContext channelHandlerContext
	 * @param msg                   msg
	 */
	@Override
	public void channelRead(ChannelHandlerContext channelHandlerContext, Object msg) {
		/*
		 * if (msg instanceof String) { if ("ping-pong-ping-pong".equals(msg)) {
		 * LOGGER.info("{} -> [心跳监测] {}：通道活跃", this.getClass().getName(),
		 * channelHandlerContext.channel().id()); // 心跳消息 lossConnectCount = 0; return;
		 * } } // 转换为MethodInvokeMeta MethodInvokeMeta invokeMeta = (MethodInvokeMeta)
		 * msg; LOGGER.info("{} -> [客户端信息] \n 方法名  - > {} \n 参数列表  -> {} \n " +
		 * "返回值  ->  {} ", this.getClass().getName(), invokeMeta.getMethodName(),
		 * invokeMeta.getArgs(), invokeMeta.getReturnType()); // 具体的处理类
		 * this.dispatcher.dispatcher(channelHandlerContext, invokeMeta);
		 */
		ByteBuf buf = (ByteBuf) msg;
		byte[] req = new byte[buf.readableBytes()];
		buf.readBytes(req);
		String body;
		try {
			body = new String(req, "GB2312");
			// 心跳消息不理
			// if(消息！=心跳){需要处理的逻辑}
			LOGGER.info("服务器端接收的消息：" + body);
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}
		ByteBuf buff = channelHandlerContext.alloc().buffer(64); // (2)
		buff.writeBytes("收到".getBytes(Charset.forName("gb2312")));
		channelHandlerContext.writeAndFlush(buff);
	}

	@Override
	public void channelActive(final ChannelHandlerContext ctx) { // (1)
		final ByteBuf buff = ctx.alloc().buffer(64); // (2)
		buff.writeBytes("连接成功".getBytes(Charset.forName("gb2312")));

		final ChannelFuture f = ctx.writeAndFlush(buff);
		f.addListener(new ChannelFutureListener() {
			public void operationComplete(ChannelFuture future) {
				assert f == future;
				// 如果拒绝连接就close掉
				// ctx.close();
			}
		});
	}

	@Override
	public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
		ctx.fireChannelReadComplete();
	}

	/**
	 * 触发器
	 *
	 * @param channelHandlerContext channelHandlerContext
	 * @param evt
	 * @throws Exception exception
	 */
	@Override
	public void userEventTriggered(ChannelHandlerContext channelHandlerContext, Object evt) throws Exception {
		LOGGER.info("{} -> [已经有60秒中没有接收到客户端的消息了]", this.getClass().getName());
		if (evt instanceof IdleStateEvent) {
			IdleStateEvent idleStateEvent = (IdleStateEvent) evt;
			if (idleStateEvent.state() == IdleState.READER_IDLE) {
				lossConnectCount++;
				if (lossConnectCount > 2) {
					LOGGER.info("{} -> [释放不活跃通道] {}", this.getClass().getName(), channelHandlerContext.channel().id());
					channelHandlerContext.channel().close();
				}
			}
		} else {
			super.userEventTriggered(channelHandlerContext, evt);
		}
	}
}
